/*
 * Indiana University Community Grid Computing Lab Software License,Version 1.1
 *
 * Copyright (c) 2002 Community Grid Computing Lab, Indiana University.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *      "This product includes software developed by the Indiana University
 *       Community Grid Computing Lab (http://www.communitygrids.iu.edu/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Indiana Univeristy","Indiana Univeristy Pervasive Techonology
 *    Labs" and  "Indiana Univeristy Community Grid Computing Lab" must not be
 *    used to endorse or promote products derived from this software without
 *    prior written permission. For written permission, please contact
 *    http://www.communitygrids.iu.edu/.
 *
 * 5. Products derived from this software may not use "Indiana
 *    University" name nor may "Indiana University" appear in their name,
 *    without prior written permission of the Indiana University.
 *
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * INDIANA UNIVERSITY OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package cgl.sensorgrid.sopac.gps.filters;

import java.io.*;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.util.*;

import cgl.narada.event.*;
import cgl.sensorgrid.filters.*;

/**
 *
 * <p>Title: Sensor Grid</p>
 *
 * <p>Copyright: Copyright (c) 2005</p>
 *
 * <p>Company: CGL</p>
 *
 * @author Galip Aydin
 * @version 1.0
 */
public class Rtd2Narada extends Filter {

    private String rtdAddress;
    private int rtdPort;
    public SocketChannel socketClient = null;
    public InetSocketAddress isa = null;
    public Selector sel = null;

    public Rtd2Narada() {
    }

    public Rtd2Narada(String[] args, String[] filterSpecificArgs) {
        if (filterSpecificArgs == null || filterSpecificArgs.length == 0) {
            System.err.println(
                    "Incorrect number of arguments in Rtd2Narada::Constructor...");
            System.exit(0);
        } else {
            this.initialize(args);
            if (filterSpecificArgs[0] != null) {
                if (filterSpecificArgs.length == 2) {
                    this.rtdAddress = filterSpecificArgs[0];
                    this.rtdPort = Integer.parseInt(filterSpecificArgs[1]);
                    // initializeSocketClient(rtdAddress, rtdPort);
                } else {
                    System.out.println(
                            "Rtd2Narada::Invalid number of arguments...");
                }
            }
        }
    }

/*
    public void initializeSocketClient(String rtdAddress, int rtdPort) {
        // Create a socket without a timeout
        try {
            Calendar cal = new GregorianCalendar();
            System.out.println("\nOpening Socket connection to RTD Server at " +
                               rtdAddress + ":" + rtdPort + "...");
            try {
                socketClient = SocketChannel.open();
                isa = new InetSocketAddress(rtdAddress, rtdPort);
                socketClient.connect(isa);
                socketClient.configureBlocking(false);
            } catch (IOException ex) {
                System.err.println(
                        "Socket connection failed...Terminating");
                System.err.println(ex.toString());
                System.exit(0);
            }

            System.out.println("Socket connection successful." +
                               "\n\n[--SensorGrid Real-Time GPS Message Processing--]\n" +
                               cal.get(Calendar.HOUR_OF_DAY) + ":" +
                               cal.get(Calendar.MINUTE) + ":" +
                               cal.get(Calendar.SECOND));

            while (true) {
                int count = 0;
                ByteBuffer buf = ByteBuffer.allocate(2048);
                buf.clear();
                byte[] by;
                while ((count = socketClient.read(buf)) > 0){
                    System.out.println("2 -> " + cal.get(Calendar.SECOND));
                    buf.flip();
                    by = new byte[count];
                    if (buf.array().length > 0) {
                        System.arraycopy(buf.array(), 0, by, 0, count);
                        if (by != null && by.length > 0) {
                            //System.out.println("Publishing");
                            publishData(by);
                            //System.out.println(new String(by));
                        }
                        cal = new GregorianCalendar();
                        //System.out.println(cal.get(Calendar.HOUR_OF_DAY) +
                        //":" +
                        //cal.get(Calendar.MINUTE) + ":" +
                        //cal.get(Calendar.SECOND) +
                        //" -- " +
                        //count + " bytes");
                        count = 0;
                        buf.clear();
                    } else {
                        System.err.println("NULL RYO Message received");
                    }
                }
                buf = null;
            }
        } catch (Exception e) {
            Calendar cal = new GregorianCalendar();

            cal = new GregorianCalendar();
            System.err.println("Exception in Rtd2Narada: " +
                               cal.get(Calendar.HOUR_OF_DAY) + ":" +
                               cal.get(Calendar.MINUTE) + ":" +
                               cal.get(Calendar.SECOND));
            e.printStackTrace();
        }
    }*/

    /**
     * Following is Ruey-Juin Chang's version of the previous Socket Client method
     *
     * @param serverAddr String
     * @param serverPort int
     */
    public void initializeClient(String serverAddr, int serverPort) {
        Calendar cal = new GregorianCalendar();
        System.out.println("\nOpening Socket connection to RTD Server at " +
                           serverAddr + ":" + serverPort + "...");
        try {
            socketClient = SocketChannel.open();
            isa = new InetSocketAddress(serverAddr, serverPort);
            socketClient.connect(isa);
            socketClient.configureBlocking(false);
            sel = Selector.open();
            socketClient.register(sel, SelectionKey.OP_READ);
        } catch (IOException ex) {
            System.out.println(
                    "Socket connection unsuccessful...Terminating");
            System.out.println(ex.toString());
            System.exit(0);
        }
        System.out.println("Socket connection successful." +
                           "\n\n[--SensorGrid Real-Time GPS Message Processing--]\n" +
                           cal.get(Calendar.HOUR_OF_DAY) + ":" +
                           cal.get(Calendar.MINUTE) + ":" +
                           cal.get(Calendar.SECOND));

        while (true) {
            try {
                int n = sel.select(300000); //time out setting is 5 minutes
                //int n = sel.select();//blocking
                //never reached here if not using time out setting
                if (n == 0) {
                    System.out.println("time out exceptions");
                    socketClient.close();
                    socketClient = SocketChannel.open();
                    socketClient.connect(isa);
                    socketClient.configureBlocking(false);
                    socketClient.register(sel, SelectionKey.OP_READ);
                    System.out.println("connected!!!");
                }
                Iterator it = sel.selectedKeys().iterator();
                while (it.hasNext()) {
                    SelectionKey key = (SelectionKey) it.next();
                    if (key.isReadable()) {
                        ByteBuffer buf = ByteBuffer.allocate(2048);
                        byte[] by;
                        int count = socketClient.read(buf);
                        if (count > 0) {
                            buf.flip();
                            by = new byte[count];
                            if (buf.array().length > 0) {
                                System.arraycopy(buf.array(), 0, by, 0, count);
                                if (by != null && by.length > 0) {
                                    publishData(by);
                                    //by is the received RYO message
                                }
                                count = 0;
                                buf.clear();
                            } else {
                                System.err.println("NULL RYO Message received");
                            }
                        } else if (count == -1) {
                            buf = null;
                            System.out.println(
                                    "end of stream or connection being closed by server");
                            socketClient.close();
                            socketClient = SocketChannel.open();
                            socketClient.connect(isa);
                            socketClient.configureBlocking(false);
                            socketClient.register(sel, SelectionKey.OP_READ);
                            System.out.println("connected!!!");
                        }
                        buf = null;
                    }
                    it.remove();
                    cal = new GregorianCalendar();
                }
            } catch (IOException ioe) {
                System.out.println("IO exception -- server stops or shutdowns");
                try {
                    if (socketClient.isOpen() || socketClient.isConnected()) {
                        System.out.println("close this connection");
                        socketClient.close();
                    }
                    System.out.println("open a new one...");
                    socketClient = SocketChannel.open();
                    socketClient.connect(isa);
                    socketClient.configureBlocking(false);
                    socketClient.register(sel, SelectionKey.OP_READ);
                    System.out.println("connected!!!");
                } catch (IOException ce) {
                    System.out.println("trying...");
                    try {
                        socketClient.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public void onEvent(NBEvent nbEvent) {
    }


    public void run() {
        try {
            initializeClient(rtdAddress, rtdPort);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static void main(String[] args) {
        try {
            if (args.length < 6) {
                System.out.println("Usage: java cgl.sensorgrid.socket.Rtd2Narada socketHost socketPort commType nbHost nbPort nbTopic");
                System.exit(0);
            }
            String socketHost = args[0];
            String socketPort = args[1];
            String commType = args[2];
            String nbHost = args[3];
            String nbPort = args[4];
            String nbTopic = args[5];

//            String socketHost = "132.239.152.69";
//            String socketPort = "5010";
//            String nbHost = "gf2.ucs.indiana.edu"; //"xsopac.ucsd.edu";
//            String nbPort = "3045";
//            String nbTopic = "/SOPAC/GPS/" + "CRTN_01" + "/RYO";
//            String commType = "niotcp";

            String[] argsa = {commType,
                             nbHost,
                             nbPort,
                             "",
                             nbTopic};
            String[] argsb = {socketHost, socketPort};

            Rtd2Narada sock = new Rtd2Narada(argsa, argsb);
            sock.run();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
